use std::{collections::BTreeMap, sync::Arc};

use parking_lot::RwLock;

use crate::data::log_record::LogRecordPos;


use super::Indexer;

// BTree 索引，主要封装了标准库中的 BTreeMap 结构
pub struct BTree {
    tree: Arc<RwLock<BTreeMap<Vec<u8>, LogRecordPos>>>,
}

impl BTree {
    pub fn new() -> Self {
        Self {
            tree: Arc::new(RwLock::new(BTreeMap::new())),
        }
    }
}



impl Indexer for BTree {
    fn put(&self, key: Vec<u8>, pos: LogRecordPos) -> bool {
        let mut wr = self.tree.write();
        wr.insert(key, pos);
        true
    }

    fn get(&self, key: Vec<u8>) -> Option<LogRecordPos> {
        let rd = self.tree.read();
        let val = rd.get(&key);
        val.copied()
    }

    fn delete(&self, key: Vec<u8>) -> bool {
        let mut wr = self.tree.write();
        wr.remove(&key).is_some()
    }
}


#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_btree_put(){

        let bt = BTree::new();
        let res1 = bt.put(
            "".as_bytes().to_vec(), 
            LogRecordPos { offset: 1, file_id: 1 },
        );
        assert_eq!(res1, true);

        let res2 = bt.put(
            "aa".as_bytes().to_vec(),   
            LogRecordPos { offset: 11, file_id: 22 },
        );
        assert_eq!(res2, true);

    }


    #[test]
    fn test_btree_get(){

        let bt = BTree::new();
        let res1 = bt.put(
            "".as_bytes().to_vec(), 
            LogRecordPos { offset: 1, file_id: 1 },
        );
        assert!(res1);

        let res2 = bt.put(
            "aa".as_bytes().to_vec(),   
            LogRecordPos { offset: 11, file_id: 22 },
        );
        assert!(res2);

        let val1 = bt.get("".as_bytes().to_vec());
        assert!(val1.is_some());
        assert_eq!(1, val1.unwrap().file_id);
        assert_eq!(1, val1.unwrap().offset);

        let val2 = bt.get("aa".as_bytes().to_vec());
        assert!(val2.is_some());
        assert_eq!(22, val2.unwrap().file_id);
        assert_eq!(11, val2.unwrap().offset);


    }


    #[test]
    fn test_btree_del() {

        let bt = BTree::new();
        let res1 = bt.put(
            "".as_bytes().to_vec(), 
            LogRecordPos { offset: 1, file_id: 1 },
        );
        assert!(res1);
        
        let val1 = bt.delete("".as_bytes().to_vec());
        assert!(val1);

        let val1 = bt.delete("".as_bytes().to_vec());
        assert!(!val1);

    }

}